package org.mq.mymq.common.event;

import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.mq.mymq.common.event.model.Event;
import org.mq.mymq.common.utils.RefactUtil;

import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName EventBust
 * @Description 事件总线
 * @Author jiarong_ye
 * @Date 2025/6/19 12:43
 * @Version 1.0
 */
public class EventBus {
    private String taskName = "event-bus-task-";
    private Map<Class<? extends Event>, List<Listener>> eventListenerMap = new ConcurrentHashMap<Class<? extends Event>, List<Listener>>();
    private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            10,
            100,
            3,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(1000),
            r -> {
                Thread thread = new Thread(r);
                thread.setName(taskName + UUID.randomUUID());
                return thread;
            });

    public EventBus(String taskName) {
        this.taskName = taskName;
    }

    public EventBus() {
    }

    public void init() {
        ServiceLoader<Listener> serviceLoader = ServiceLoader.load(Listener.class);
        for (Listener listener : serviceLoader) {
            Class interfaceT = RefactUtil.getInterfaceT(listener, 0);
            this.registry(interfaceT, listener);
        }
        threadPoolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    }

    private <E extends Event> void registry(Class<? extends Event> clazz, Listener<E> listener) {
        List<Listener> listeners = eventListenerMap.get(clazz);
        if (CollectionUtils.isEmpty(listeners)) {
            eventListenerMap.put(clazz, Lists.newArrayList(listener));
        } else {
            listeners.add(listener);
            eventListenerMap.put(clazz, listeners);
        }
    }

    public void publish(Event event) {
        List<Listener> listeners = eventListenerMap.get(event.getClass());
        threadPoolExecutor.execute(() -> {
            try {
                for (Listener listener : listeners) {
                    listener.onReceive(event);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    public String getTaskName() {
        return taskName;
    }

    public void setTaskName(String taskName) {
        this.taskName = taskName;
    }

    public static void main(String[] args) {
//        EventBus eventBus = new EventBus();
//        eventBus.init();
    }
}
